#ifndef JCONCURRENT_RUNBASE_H
#define JCONCURRENT_RUNBASE_H

#include "jconcurrent_global.h"
#include "jfuture.h"
#include "jrunnable.h"
#include "jthreadpool.h"

namespace JConcurrent {

template <typename T>
struct SelectSpecialization
{
    template <class Normal, class Void>
    struct Type { typedef Normal type; };
};

template <>
struct SelectSpecialization<void>
{
    template <class Normal, class Void>
    struct Type { typedef Void type; };
};

template <typename T>
class RunFunctionTaskBase : public JFutureInterface<T> , public JRunnable
{
public:
    JFuture<T> start()
    {
        this->setRunnable(this);
        this->reportStarted();
        JFuture<T> future = this->future();
        JThreadPool::globalInstance().start(this, /*m_priority*/ 0);
        return future;
    }

    void run() {}
    virtual void runFunctor() = 0;
};

template <typename T>
class RunFunctionTask : public RunFunctionTaskBase<T>
{
public:
    void run()
    {
        if (this->isCanceled()) {
            this->reportFinished();
            return;
        }
        try {
            this->runFunctor();
        } catch (JConcurrent::Exception &e) {
            JFutureInterface<T>::reportException(e);
        } catch (...) {
            JFutureInterface<T>::reportException(JConcurrent::UnhandledException());
        }

        this->reportResult(result);
        this->reportFinished();
    }
    T result;
};

template <>
class RunFunctionTask<void> : public RunFunctionTaskBase<void>
{
public:
    void run()
    {
        if (this->isCanceled()) {
            this->reportFinished();
            return;
        }
        try {
            this->runFunctor();
        } catch (JConcurrent::Exception &e) {
            JFutureInterface<void>::reportException(e);
        } catch (...) {
            JFutureInterface<void>::reportException(JConcurrent::UnhandledException());
        }

        this->reportFinished();
    }
};

} //namespace JConcurrent

#endif  // JCONCURRENT_RUNBASE_H
